package cn.jiangjiesheng.bootstrap.filestore;

import cn.jiangjiesheng.bootstrap.filestore.impl.*;
import cn.jiangjiesheng.bootstrap.filestore.properties.FileStoreProperties;
import cn.jiangjiesheng.bootstrap.filestore.dto.ResultMap;
import cn.jiangjiesheng.bootstrap.filestore.exception.UnsupportedFileStoreBackend;
import cn.jiangjiesheng.bootstrap.filestore.impl.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;

import javax.annotation.PostConstruct;
import java.io.InputStream;
import java.util.Date;
import java.util.Objects;

/**
 * 文件存储模块
 * <p>
 * Created by dev@jiangjiesheng.cn on 2021/7/9  <br/>
 */
@Slf4j
@NoArgsConstructor
public class FileStoreClient implements IFileStoreOperator {

    @SuppressWarnings("rawtypes")
    private AbstractFileStore fileStore;

    @Getter
    @Setter
    private FileStoreProperties fileStoreProperties;

    public FileStoreClient(FileStoreProperties fileStoreProperties) {
        this.fileStoreProperties = fileStoreProperties;
        this.initialize();
    }

    @PostConstruct
    public void initialize() {
        if (!fileStoreProperties.isEnabled()) {
            log.info("file store is disabled.");
            return;
        }
        propertiesValidation();
        switch (fileStoreProperties.getStoreBackend()) {
            case MINIO:
                fileStore = new MinioFileStore(fileStoreProperties);
                break;
            case ALI_OSS:
                fileStore = new AliyunOssFile(fileStoreProperties);
                break;
            case HUAWEI_OBS:
                fileStore = new HuaweiObsFileStore(fileStoreProperties);
                break;
            default:
                throw new UnsupportedFileStoreBackend();
        }
    }

    /**
     * 校验properties是否符合预期
     */
    private void propertiesValidation() {
        if (fileStoreProperties.isEnabled()) {
            Assert.isTrue(StringUtils.isNoneBlank(fileStoreProperties.getAk()), "property ak is required.");
            Assert.isTrue(StringUtils.isNoneBlank(fileStoreProperties.getSk()), "property sk is required.");
            Assert.isTrue(StringUtils.isNoneBlank(fileStoreProperties.getEndpoint()), "property endpoint is required.");
            Assert.isTrue(Objects.nonNull(fileStoreProperties.getStoreBackend()), "property storeBackend is required.");
        }
    }

    @Override
    public String putBigObject(String bucket, String objectId, String filepath) {
        return fileStore.putBigObject(bucket, objectId, filepath);
    }

    @Override
    public String putBigObject(String objectId, String filepath) {
        return this.putBigObject(getFileStoreProperties().getDefaultBucket(), objectId, filepath);
    }

    @Override
    public void putObject(String bucket, String objectId, InputStream fileData) {
        fileStore.putObject(bucket, objectId, fileData);
    }

    @Override
    public InputStream getObject(String bucket, String objectId) {
        return fileStore.getObject(bucket, objectId);
    }

    /**
     * 开启公共读（enabled=true）
     * @param bucket
     * @param objectId
     * @param enabled
     */
    @Override
    public void publicRead(String bucket, String objectId, boolean enabled) {
        fileStore.publicRead(bucket, objectId, enabled);
    }

    /**
     * 开启公共读（enabled=true）
     * @param objectId
     * @param enabled
     */
    @Override
    public void publicRead(String objectId, boolean enabled) {
        fileStore.publicRead(getFileStoreProperties().getDefaultBucket(), objectId, enabled);
    }


    @Override
    public void copyObject(String bucket, String objectId, String targetBucket, String targetObjectId) {
        fileStore.copyObject(bucket, objectId, targetBucket, targetObjectId);
    }

    @Override
    public Boolean doesBucketExists(String bucket) {
        return fileStore.doesBucketExists(bucket);
    }

    @Override
    public void createBucket(String bucket) {
        fileStore.createBucket(bucket);
    }

    @Override
    public void deleteObject(String bucket, String objectId) {
        fileStore.deleteObject(bucket, objectId);
    }

    @Override
    public ResultMap deleteMultipleObjects(String bucket, String... objectIds) {
        return fileStore.deleteMultipleObjects(bucket, objectIds);
    }

    @Override
    public ResultMap doesObjectsExists(String bucket, String... objectIds) {
        return fileStore.doesObjectsExists(bucket, objectIds);
    }

    @Override
    public Boolean doesObjectExists(String bucket, String objectId) {
        return fileStore.doesObjectExists(bucket, objectId);
    }

    @Override
    public ResultMap getObjectMeta(String bucket, String objectId) {
        return fileStore.getObjectMeta(bucket, objectId);
    }

    @Override
    public ResultMap generatePreSignedURL(String bucket, String... objectIds) {
        return fileStore.generatePreSignedURL(bucket, objectIds);
    }

    @Override
    public ResultMap generatePreSignedURL(String bucket, Date expiration, String... objectIds) {
        return fileStore.generatePreSignedURL(bucket, expiration, objectIds);
    }

    @Override
    public void putObject(String objectId, InputStream fileData) {
        this.putObject(this.getFileStoreProperties().getDefaultBucket(), objectId, fileData);
    }

    @Override
    public InputStream getObject(String objectId) {
        return this.getObject(getFileStoreProperties().getDefaultBucket(), objectId);
    }

    @Override
    public void deleteObject(String objectId) {
        this.deleteObject(getFileStoreProperties().getDefaultBucket(), objectId);
    }

    @Override
    public ResultMap deleteMultipleObjects(String... objectIds) {
        return this.deleteMultipleObjects(getFileStoreProperties().getDefaultBucket(), objectIds);
    }

    @Override
    public ResultMap doesObjectsExists(String... objectIds) {
        return this.doesObjectsExists(getFileStoreProperties().getDefaultBucket(), objectIds);
    }

    @Override
    public Boolean doesObjectExists(String objectId) {
        return this.doesObjectExists(getFileStoreProperties().getDefaultBucket(), objectId);
    }

    @Override
    public ResultMap getObjectMeta(String objectId) {
        return this.getObjectMeta(getFileStoreProperties().getDefaultBucket(), objectId);
    }

    @Override
    public ResultMap generatePreSignedURL(String... objectIds) {
        return this.generatePreSignedURL(getFileStoreProperties().getDefaultBucket(), objectIds);
    }

    @Override
    public ResultMap generatePreSignedURL(Date expiration, String... objectIds) {
        return this.generatePreSignedURL(getFileStoreProperties().getDefaultBucket(), expiration, objectIds);
    }

    @Override
    public ResultMap generatePreSignedURL(String objectId) {
        return this.generatePreSignedURL(getFileStoreProperties().getDefaultBucket(), new String[]{objectId});
    }

    @Override
    public void close() {
        fileStore.close();
    }
}
